﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace DllInjector
{
    class Injector
    {
        /// <summary>
        /// Creates Win32 process.
        /// </summary>
        /// <param name="filepath">Path to the target application.</param>
        /// <param name="processCreationFlags">Process creation flags</param>
        /// <returns>Returns Win32.ProcessInfo</returns>
        public static Win32.ProcessInfo CreateProcess(string filepath, Win32.ProcessCreationFlags creationFlags)
        {
            Win32.StartupInfo startInfo = new Win32.StartupInfo();
            Win32.ProcessInfo procInfo = new Win32.ProcessInfo();
            Win32.SecurityAttributes pSec = new Win32.SecurityAttributes();
            Win32.SecurityAttributes tSec = new Win32.SecurityAttributes();

            pSec.length = Marshal.SizeOf(pSec);
            tSec.length = Marshal.SizeOf(tSec);

            Win32.CreateProcess(
                filepath,
                string.Empty,
                ref pSec,
                ref tSec,
                false,
                (uint)creationFlags,
                IntPtr.Zero,
                null,
                ref startInfo,
                out procInfo
                );

            return procInfo;
        }

        /// <summary>
        /// Inject .DLL into program.
        /// </summary>
        /// <param name="process">Process handle</param>
        /// <param name="dllPath">Path to the .DLL file</param>
        /// <returns>Returns true if function succeed.</returns>
        public static bool InjectDll(Process process, string dllPath)
        {
            IntPtr hDll = Win32.LoadLibrary("kernel32");
            if (hDll == IntPtr.Zero)
            {
                return false;
            }

            IntPtr LoadLibraryAddress = Win32.GetProcAddress(hDll, "LoadLibraryA");
            if (LoadLibraryAddress == IntPtr.Zero)
            {
                Win32.FreeLibrary(hDll);
                return false;
            }

            IntPtr paramAddr = Win32.VirtualAllocEx(process.Handle, 0, (uint)(dllPath.Length + 1), Win32.MemoryAllocType.MEM_COMMIT, Win32.MemoryProtectType.PAGE_READWRITE);

            IntPtr bytesWritten = IntPtr.Zero;
            byte[] buffer = UTF8Encoding.UTF8.GetBytes(dllPath);
            bool memoryWritten = Win32.WriteProcessMemory(process.Handle, paramAddr, buffer, (uint)(dllPath.Length + 1), out bytesWritten);

            IntPtr funcThread = Win32.CreateRemoteThread(process.Handle, 0, 0, LoadLibraryAddress, paramAddr, 0, 0);
            if (funcThread != IntPtr.Zero)
            {
                uint exit_code = Win32.WaitForSingleObject(funcThread, uint.MaxValue);
                Win32.CloseHandle(funcThread);
            }

            if (hDll != IntPtr.Zero)
            {
                Win32.FreeLibrary(hDll);
            }
            return true;
        }

        /// <summary>
        /// Inject .DLL into program.
        /// </summary>
        /// <param name="process">Process handle</param>
        /// <param name="dllPath">Path to the .DLL file</param>
        /// <returns>Returns true if function succeed.</returns>
        public static bool EjectDll(Process process, uint moduleBaseAddress)
        {
            IntPtr hDll = Win32.LoadLibrary("kernel32");
            if (hDll == IntPtr.Zero)
            {
                return false;
            }

            IntPtr FreeLibraryAddress = Win32.GetProcAddress(hDll, "FreeLibrary");
            if (FreeLibraryAddress == IntPtr.Zero)
            {
                Win32.FreeLibrary(hDll);
                return false;
            }

            IntPtr funcThread = Win32.CreateRemoteThread(process.Handle, 0, 0, FreeLibraryAddress, new IntPtr(moduleBaseAddress), 0, 0);
            if (funcThread != IntPtr.Zero)
            {
                uint exit_code = Win32.WaitForSingleObject(funcThread, uint.MaxValue);
                Win32.CloseHandle(funcThread);
            }

            if (hDll != IntPtr.Zero)
            {
                Win32.FreeLibrary(hDll);
            } 
            return true;
        }

        
        public static bool CallDllFunction(Process process, IntPtr dllBaseAddress, string functionName, int functionParameter)
        {
            throw new NotImplementedException("Not implemented yet.");
        }
    }
}
